package com.jamin.aabill.http;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import org.json.JSONException;
import org.json.JSONObject;

import com.jamin.aabill.api.BillException;
import com.jamin.aabill.sharepref.SharePrefConstant;
import com.jamin.aabill.ui.AABillApplication;
import com.jamin.aabill.utils.Utils;



public class Response {


	private static final String TAG = "Response";
	private int statusCode = -1;
	private String sessionId = "";
	private String responseAsString = null;
	private InputStream is;
	private HttpURLConnection con;
	private boolean streamConsumed = false;

	public Response()  {

	}



	public Response(HttpURLConnection con) throws IOException {
		this.con = con;
		this.statusCode = con.getResponseCode();
		con.getHeaderField("");
		if(null == (is = con.getErrorStream())){
			is = con.getInputStream();
		}
		if (null != is && "gzip".equals(con.getContentEncoding())) {
			// the response is gzipped
			is = new GZIPInputStream(is);
		}
		String cookieVal = con.getHeaderField("set-cookie");
		if(cookieVal != null) 
		{ 
			sessionId = cookieVal.substring(0, cookieVal.indexOf(";"));
			AABillApplication.mSharedPref.putSharePrefString(SharePrefConstant.SESSION, sessionId);
		} 
		Utils.log(TAG, "cookie = " + getSessionId());
		
	}

	/**
	 * 
	 * @method getStatusCode
	 * @return
	 * @throws 
	 * @since v1.0
	 */
	public int getStatusCode(){
		return statusCode;
	}


	/**
	 * 
	 * @return SessionId();
	 */
	public String getSessionId(){
		return sessionId;
	}
	/**
	 * Returns the response body as string.<br>
	 * Disconnects the internal HttpURLConnection silently.
	 * @return response body
	 * @throws BillException
	 */
	public String asString() throws BillException{
		if(null == responseAsString){
			BufferedReader br;
			try {
				InputStream stream = asStream();
				if (null == stream) {
					return null;
				}
				br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
				StringBuffer buf = new StringBuffer();
				String line;
				while (null != (line = br.readLine())) {
					buf.append(line).append("\n");
				}
				this.responseAsString = buf.toString();
				//				if(Configuration.isDalvik()){
				this.responseAsString = unescape(responseAsString);
				//				}
				Utils.log(TAG ,responseAsString);
				stream.close();
				con.disconnect();
				streamConsumed = true;
			} catch (NullPointerException npe) {
				// don't remember in which case npe can be thrown
				throw new BillException(npe.getMessage(), npe);
			} catch (IOException ioe) {
				throw new BillException(ioe.getMessage(), ioe);
			}
		}
		return responseAsString;
	}

	/**
	 * Returns the response body as sinat4j.org.json.JSONObject.<br>
	 * Disconnects the internal HttpURLConnection silently.
	 * @return response body as sinat4j.org.json.JSONObject
	 * @throws BillException
	 */
	public JSONObject asJSONObject() throws BillException {
		try {
			return new JSONObject(asString());
		} catch (JSONException jsone) {
			throw new BillException(jsone.getMessage() + ":" + this.responseAsString, jsone);
		}
	}

	/**
	 * Returns the response stream.<br>
	 * This method cannot be called after calling asString() or asDcoument()<br>
	 * It is suggested to call disconnect() after consuming the stream.
	 *
	 * Disconnects the internal HttpURLConnection silently.
	 * @return response body stream
	 * @throws BillException
	 * @see #disconnect()
	 */
	public InputStream asStream() {
		if(streamConsumed){
			throw new IllegalStateException("Stream has already been consumed.");
		}
		return is;
	}




	/**
	 * Unescape UTF-8 escaped characters to string.
	 * @author pengjianq...@gmail.com
	 *
	 * @param original The string to be unescaped.
	 * @return The unescaped string
	 */
	public static String unescape(String original) {
		Matcher mm = escaped.matcher(original);
		StringBuffer unescaped = new StringBuffer();
		while (mm.find()) {
			mm.appendReplacement(unescaped, Character.toString(
					(char) Integer.parseInt(mm.group(1), 10)));
		}
		mm.appendTail(unescaped);
		return unescaped.toString();
	}

	private static Pattern escaped = Pattern.compile("&#([0-9]{3,5});");

}